package com.clementheliou.cheliou.dal.model.city.builder;

import org.springframework.util.Assert;

import com.clementheliou.cheliou.dal.dao.city.CityDAO;
import com.clementheliou.cheliou.dal.dao.country.CountryDAO;
import com.clementheliou.cheliou.dal.model.city.City;
import com.clementheliou.cheliou.dal.model.country.builder.CountryBuilder;
import com.clementheliou.cheliou.util.builder.ObjectBuilder;

/**
 * Builder used to get {@link City} instances for test purpose. It must only be used through one of
 * its static factory methods.
 * 
 * @author Clément HELIOU (clement.heliou@gmail.com)
 * @see {@link City};
 * @see {@link ObjectBuilder}.
 * @since 1.0
 */
public class CityBuilder extends ObjectBuilder<City> {

	/**
	 * The {@link CityDAO} to be used to persist the built instance if needed.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	private final CityDAO cityDAO;

	/**
	 * The {@link CountryDAO} to be transmitted to the {@link CountryBuilder} if the instance must
	 * be persisted.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @see {@link CountryBuilder} .
	 * @since 1.0
	 */
	private final CountryDAO countryDAO;

	/**
	 * Private constructor from the DAO's to be used. It's creates a default instance ready to be
	 * persisted.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param cityDAO the {@link CityDAO} to be used.
	 * @param countryDAO the {@link CountryDAO} to be used.
	 * @since 1.0
	 */
	private CityBuilder(CityDAO cityDAO, CountryDAO countryDAO) {
		this.cityDAO = cityDAO;
		this.countryDAO = countryDAO;
	}

	/**
	 * Static factory method used to get a builder instance for a {@link City} object that must be
	 * persistent. It's mostly used on data access layer's methods tests.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param cityDAO the {@link CityDAO} to be used.
	 * @param countryDAO the {@link CountryDAO} to be used.
	 * @return the builder instance to be used.
	 * @since 1.0
	 */
	public static CityBuilder with(CityDAO cityDAO, CountryDAO countryDAO) {
		return new CityBuilder(cityDAO, countryDAO);
	}

	/**
	 * Creates a default {@link City} instance, ready to be persisted.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the builder instance to be used.
	 * @since 1.0
	 */
	public CityBuilder createDefaultCity() {
		setInstance(createInstance());
		return this;
	}

	/**
	 * Persists the built {@link City} instance then flush the current session.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the builder instance after this action.
	 * @since 1.0
	 */
	public CityBuilder persistAndFlush() {
		Assert.notNull(cityDAO, "cityDAO must not be null at this time");

		cityDAO.saveEntity(getObject());
		cityDAO.flushSession();
		return this;
	}

	/**
	 * Creates a {@link City} instance with default values. These ones have a functional sense.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the built instance.
	 * @since 1.0
	 */
	private City createInstance() {
		Assert.notNull(countryDAO, "countryDAO must not be null at this time");

		final City defaultCity = new City();
		defaultCity.setCountry(CountryBuilder.with(countryDAO).createDefaultCountry().persistAndFlush().getObject());
		defaultCity.setName("Paris VI");
		defaultCity.setZipCode("75006");

		return defaultCity;
	}
}
